/** @file intersection.h
    @brief Intersection mathematics */
#ifndef G3_INTERSECTION_H
#define G3_INTERSECTION_H

#include "log.h"

#include "m_vector.h"
#include "m_plane.h"

#include <stdio.h>
#include <vector>

namespace G3 {

/** @class INTERSECTION
    @brief A general intersection base class */
//template <class T>
class INTERSECTION {
    public:
        /**
            @brief A constructor
        */
        INTERSECTION ();

        /** Distance between the first point of the line fragment and the intersection point */
        //T Distance;
        double Distance;

        /** Intersection flag bits */
		enum FLAGS {
		    /** Intersection point lies within the line fragment */
		    INT_LINE_FRAG = 1,
		    /** Intersection point lies outside the line fragment (on the ray) */
		    INT_RAY = 2,
		    /** Intersection point lies inside the polygon */
		    INT_POLY = 4,
		    /** Intersection lies on all planes */
		    INT_PLANES = 8,
		    /** (BSP) Whether or not the line segment starts outside a brush */
		    INT_STARTS_OUT = 16,
		    /** (BSP) Whether or not the line segment ends outside a brush */
		    INT_ENDS_OUT = 32,
		    /** (BSP) Whether or not the line segment lies totally inside a brush */
		    INT_ALL_SOLID = 64
		};

        /** Intersection flags */
		byte Flags;
};

/** @class INTERSECTION2
    @brief 2D intersection point */
template <class T>
class INTERSECTION2: public INTERSECTION {
	public:
        /**
            @brief A constructor
        */
		INTERSECTION2 ();

        /** Intersection point */
		VEC2<T> Point;

		INTERSECTION2<T>& operator=(const INTERSECTION2<T> &I);
};

/** @class INTERSECTION3
    @brief 3D intersection point */
template <class T>
class INTERSECTION3: public INTERSECTION {
	public:
        /**
            @brief Constructor
        */
		INTERSECTION3 ();

        /** Intersection point */
		VEC3<T> Point;

		INTERSECTION3<T>& operator=(const INTERSECTION3<T> &I);
};

template <class T>
class RAY2 {
	public:
		RAY2 ();
		RAY2 (const VEC2<T> &Point0, const VEC2<T> &Point1);

		VEC2<T> a;
		VEC2<T> b;

//==============================================================================
// Just returns the directional vector between a and b
//==============================================================================
		VEC2<T> GetVector () const;
};

template <class T>
class RAY3 {
	public:
		RAY3 ();
		RAY3 (const VEC3<T> &Point0, const VEC3<T> &Point1);

		VEC3<T> a;
		VEC3<T> b;

//==============================================================================
// Just returns the directional vector between a and b
//==============================================================================
		VEC3<T> GetVector () const;

		double GetDistance (const VEC3<T> &p) const;
};

template <class T>
class POLYGON3 {
	public:
		typedef VEC3<T> VEC3X;
		typedef VEC2<T> VEC2X;

		std::vector<VEC3X> Vertices;
		std::vector<VEC2X> TexCoords;
		std::vector<VEC3X> Normals;
		PLANE3<T> Plane;

		POLYGON3<T>& operator= (const POLYGON3<T> &p);
		bool operator== (const POLYGON3<T> &p) const;

//==============================================================================
// Just calculates the plane of the polygon
//==============================================================================
		void CalcPlane ();

		void Clear ();
};

//==============================================================================
// Checks two 2D rays for intersection
//==============================================================================
template <class T>
INTERSECTION2<T> RayRayIntersection (const RAY2<T> &a, const RAY2<T> &b);

//==============================================================================
// Checks if a point is in a triangle
//==============================================================================
template <class T>
bool IsPointInTriangle (const VEC3<T> &A, const VEC3<T> &B, const VEC3<T> &C, const VEC3<T> &Point);

//==============================================================================
// Calculates Ray - Plane intersection
//==============================================================================
template <class T>
INTERSECTION3<T> RayPlaneIntersection (const PLANE3<T> &Plane, const RAY3<T> &Ray);

//==============================================================================
// Calculates Ray - Triangle intersection
//==============================================================================
template <class T>
INTERSECTION3<T> RayTriIntersection (const PLANE3<T> &Plane, const VEC3<T> &A, const VEC3<T> &B, const VEC3<T> &C, const RAY3<T> &Ray);

//==============================================================================
// Finds an intersection point between 3 planes
//==============================================================================
template <class T>
INTERSECTION3<T> Intersect3Planes (const PLANE3<T> &Plane1, const PLANE3<T> &Plane2, const PLANE3<T> &Plane3);

//==============================================================================
// A simple Sutherland Hodgeman-style polygon splitting
//==============================================================================
template <class T>
void SplitPolygonByPlane (const POLYGON3<T> &Poly, const PLANE3<T> &Plane, POLYGON3<T> *Front, POLYGON3<T> *Back);

//==============================================================================
// Classifies a polygon in respect to a plane
//==============================================================================
template <class T>
HALFSPACE PlaneClassifyPolygon (const PLANE3<T> &Plane, const POLYGON3<T> &Poly);

//==============================================================================
// Classifies a triangle in respect to a plane
//==============================================================================
template <class T>
HALFSPACE PlaneClassifyTriangle (const PLANE3<T> &Plane, const VEC3<T> &A, const VEC3<T> &B, const VEC3<T> &C);

//==============================================================================
// Triangulates a regular polygon
//==============================================================================
template <class T>
std::vector<POLYGON3<T> > TriangulateRegPoly (const POLYGON3<T> &Polygon);

//==============================================================================
// Returns minimal vertex distance to the regression line of a polygon
//==============================================================================
template <class T>
double MinDistRegression (const POLYGON3<T> &Polygon);

//==============================================================================
// Tests if a point is inside a triangle
//==============================================================================
/*template <class T>
bool TestPointTriangle (const VEC3<T> &P, const VEC3<T> &A, const VEC3<T> &B, const VEC3<T> &C);*/

//==============================================================================
// Explicit template instantiation
//==============================================================================
extern template class INTERSECTION2<float>;
extern template class INTERSECTION2<double>;
extern template class INTERSECTION3<float>;
extern template class INTERSECTION3<double>;

extern template class RAY2<float>;
extern template class RAY2<double>;
extern template class RAY3<float>;
extern template class RAY3<double>;

extern template class POLYGON3<float>;
extern template class POLYGON3<double>;

extern template INTERSECTION2<float> RayRayIntersection (const RAY2<float> &a, const RAY2<float> &b);
extern template INTERSECTION2<double> RayRayIntersection (const RAY2<double> &a, const RAY2<double> &b);

extern template bool IsPointInTriangle (const VEC3<float> &A, const VEC3<float> &B, const VEC3<float> &C, const VEC3<float> &Point);
extern template bool IsPointInTriangle (const VEC3<double> &A, const VEC3<double> &B, const VEC3<double> &C, const VEC3<double> &Point);

extern template INTERSECTION3<float> RayPlaneIntersection (const PLANE3<float> &Plane, const RAY3<float> &Ray);
extern template INTERSECTION3<double> RayPlaneIntersection (const PLANE3<double> &Plane, const RAY3<double> &Ray);

extern template INTERSECTION3<float> RayTriIntersection (const PLANE3<float> &Plane, const VEC3<float> &A, const VEC3<float> &B, const VEC3<float> &C, const RAY3<float> &Ray);
extern template INTERSECTION3<double> RayTriIntersection (const PLANE3<double> &Plane, const VEC3<double> &A, const VEC3<double> &B, const VEC3<double> &C, const RAY3<double> &Ray);

extern template INTERSECTION3<float> Intersect3Planes (const PLANE3<float> &Plane1, const PLANE3<float> &Plane2, const PLANE3<float> &Plane3);
extern template INTERSECTION3<double> Intersect3Planes (const PLANE3<double> &Plane1, const PLANE3<double> &Plane2, const PLANE3<double> &Plane3);

extern template void SplitPolygonByPlane (const POLYGON3<float> &Poly, const PLANE3<float> &Plane, POLYGON3<float> *Front, POLYGON3<float> *Back);
extern template void SplitPolygonByPlane (const POLYGON3<double> &Poly, const PLANE3<double> &Plane, POLYGON3<double> *Front, POLYGON3<double> *Back);

extern template HALFSPACE PlaneClassifyPolygon (const PLANE3<float> &Plane, const POLYGON3<float> &Poly);
extern template HALFSPACE PlaneClassifyPolygon (const PLANE3<double> &Plane, const POLYGON3<double> &Poly);

extern template HALFSPACE PlaneClassifyTriangle (const PLANE3<float> &Plane, const VEC3<float> &A, const VEC3<float> &B, const VEC3<float> &C);
extern template HALFSPACE PlaneClassifyTriangle (const PLANE3<double> &Plane, const VEC3<double> &A, const VEC3<double> &B, const VEC3<double> &C);

extern template std::vector<POLYGON3<float> > TriangulateRegPoly (const POLYGON3<float> &Polygon);
extern template std::vector<POLYGON3<double> > TriangulateRegPoly (const POLYGON3<double> &Polygon);

extern template double MinDistRegression (const POLYGON3<float> &Polygon);
extern template double MinDistRegression (const POLYGON3<double> &Polygon);

/*extern template bool TestPointTriangle (const VEC3<int> &P, const VEC3<int> &A, const VEC3<int> &B, const VEC3<int> &C);
extern template bool TestPointTriangle (const VEC3<float> &P, const VEC3<float> &A, const VEC3<float> &B, const VEC3<float> &C);
extern template bool TestPointTriangle (const VEC3<double> &P, const VEC3<double> &A, const VEC3<double> &B, const VEC3<double> &C);*/

//==============================================================================
// Types
//==============================================================================
typedef INTERSECTION2<float>	INTERSECTION2F;
typedef INTERSECTION2<double>	INTERSECTION2D;
typedef INTERSECTION3<float>	INTERSECTION3F;
typedef INTERSECTION3<double>	INTERSECTION3D;

typedef RAY2<float>				RAY2F;
typedef RAY2<double>			RAY2D;
typedef RAY3<float>				RAY3F;
typedef RAY3<double>			RAY3D;

typedef POLYGON3<float>			POLYGON3F;
typedef POLYGON3<double>		POLYGON3D;

}

#endif
